use std::ops::Deref;

#[derive(Debug)]
struct Person {
    name: String,
    age: u8,
}
impl Person {
    fn new(name: String, age: u8) -> Person {
        Person { name, age }
    }
    //智能指针，能不让你写出 ****s形式的解引用
    //名称来源，主要是其实现了Deref和Drop特征
    //Deref 可以让智能指针像引用那样工作，这样你就可以写出同时支持智能指针和引用的代码
    //Drop 允许你指定智能指针超出作用域后自动执行的代码，例如做一些数据清理等收尾工作
    fn display(self: &mut Person, age: u8) {
        self.age = age;
    }
}
#[test]
pub fn test_person() {
    let mut person = Person::new("xiaoming".to_string(), 18);
    person.display(18);
    println!("{},{}", person.name, person.age);
    println!("{:?}", person);
}

#[test]
pub fn test_deref() {
    let x = 5;
    let y = &x;
    assert_eq!(5, x);
    //引用无法和值比较
    //assert_eq!(5, y);
    assert_eq!(5, *y);
}
//=====智能指针解引用========
#[test]
fn test_box_deref(){
    let x = Box::new(1);
    //智能指针被 * 解引用
    let sum = *x + 1;
    assert_eq!(2, sum);
}
//=====定义自己的智能指针======
struct MyBox<T>(T);
impl<T> MyBox<T> {
    fn new(x: T) -> MyBox<T> {
        MyBox(x)
    }
}
impl<T> Deref for MyBox<T> {
    type Target = T;
    fn deref(&self) -> &T {
        &self.0
    }
    //当解引用 MyBox 智能指针时，返回元组结构体中的元素 &self.0
    //在 Deref 特征中声明了关联类型 Target，在之前章节中介绍过，关联类型主要是为了提升代码可读性
    //deref 返回的是一个常规引用，可以被 * 进行解引用
}

#[test]
fn test_mybox(){
    let x = MyBox::new(5);
    //如果MyBox没有实现Deref特征，则无法通过 * 解引用
    assert_eq!(5, *x);
}
//解引用运算符 *y 实际上Rust为我们调用了deref方法 *(y.deref())

//===函数和方法中的隐式 Deref 转换=========

//String 实现了 Deref 特征，可以在需要时自动被转换为 &str 类型
// &s 是一个 &String 类型，当它被传给 display 函数时，自动通过 Deref 转换成了 &str
// 必须使用 &s 的方式来触发 Deref(仅引用类型的实参才会触发自动解引用)

//======连续的隐式 Deref 转换=====
